package com.dorukdestan.p2pshare.storage;

import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.dorukdestan.p2pshare.logger.Logger;
import com.dorukdestan.p2pshare.model.Constants;
import com.dorukdestan.p2pshare.network.QueryClient;

public class PeerList implements Serializable{

	private static final long serialVersionUID = -433814901613844789L;

	private static Logger logger;
	private static long lastUpdate;
	private static ArrayList<InetAddress> nearestPeersUnsynchronized;
	private static List<InetAddress> nearestPeers;

	private static boolean ready;
	
	static{
		logger = new Logger(PeerList.class);
		lastUpdate = 0;
		nearestPeersUnsynchronized = new ArrayList<InetAddress>();
		nearestPeers = Collections.synchronizedList(nearestPeersUnsynchronized);
		ready = true;
	}
	
	private static boolean isUpToDate(){
		return (System.currentTimeMillis() - lastUpdate) < Constants.timeoutForNearestPeersValidation;
	}
	
	/**
	 * Adds a new peer to the nearest peers list if list is not up to date
	 * or list is up to date but not populated enough.<br><br>
	 * 
	 * Note that this method does not create a new thread
	 * 
	 * @param inetAddress
	 */
	public synchronized static void addPeer(InetAddress inetAddress){
		
		if(!isUpToDate()){
			//Create the list over again
			lastUpdate = System.currentTimeMillis();
			nearestPeersUnsynchronized = new ArrayList<InetAddress>();
			nearestPeers = Collections.synchronizedList(nearestPeersUnsynchronized);
			nearestPeers.add(inetAddress);
			ready = true;
		}	
		else if( nearestPeers.size() < Constants.NEAREST_PEERS_NUM){
			//Add new peer
			nearestPeers.add(inetAddress);
			ready = true;
		}
		
		
		logger.debug("Nearest peers:");
		for (InetAddress address : nearestPeers) {
			logger.debug(address.getHostAddress());
		}
	}
	
	public synchronized static void updateNearestPeers(){
		if(!isUpToDate()){
			ready = false;
			QueryClient.sendHello();
		}
		else{
			logger.debug("Peer list up to date.");
		}
	}
	
	public static InetAddress[] getNearestPeers(){
		return nearestPeers.toArray(new InetAddress[0]);
	}
	
	public static void waitUntillReady(){
		long start = System.currentTimeMillis();
		
		logger.debug("Waiting for peer list to be updated");
		
		while(System.currentTimeMillis() - start < Constants.timeoutForGettingAnswers && !ready){
			logger.debug(".");
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {}
		}
		
		logger.debug("Peer list updated, size: " + nearestPeers.size());
	}
	
}
